home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / NextAnswers / 1320_message_overhead.rtf < prev    next >
Text File  |  1995-06-12  |  4KB  |  60 lines

  1. {\rtf0\ansi{\fonttbl\f0\fnil Times-Roman;\f1\fmodern Courier;\f2\fmodern Ohlfs;}
  2. \paperw13040
  3. \paperh10200
  4. \margl120
  5. \margr120
  6. {\colortbl;\red84\green84\blue84;\red83\green83\blue83;}
  7. \pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600\f0\b0\i0\ulnone\fs28\fc0\cf0 Q:  My Objective-C messages take too long compared with C function calls.  What can I do?\
  8. \
  9. A:  We have chosen to pay a certain performance cost in exchange for the benefits of object-oriented programming.  What is really important is to amortize the added overhead of a message send over the cost of running your program.  The cost of writing and maintaining correct code is also a consideration.\
  10. \
  11. There is a way to optimize tight loops in code.  The method "methodFor:" returns a pointer to the actual function used to implement a method.  This can be used at the beginning of a tight loop to cache the call.  Example:\
  12. \
  13.  
  14. \f1\fs24     IMP func;\
  15.     \
  16.     func = [anObject methodFor:aSelector];\
  17.     while (loopingTightly) \{\
  18.         ...\
  19.         func(anObject, @selector(aSelector), args ...);\
  20.         ...\
  21.     \}\
  22.  
  23. \f0\fs28 \
  24. As long as anObject is not changing value in that inner loop, then this technique does not sacrifice any of the advantages of Objective-C (e.g., dynamic binding) and is just as efficient as normal C.\
  25. \
  26. However, there is a very subtle error that can be introduced by using the methodFor: method to get the pointer to the implementation of a method.   methodFor: returns an IMP which is a pointer to a function which returns an id.  It is prototyped to take an id, a SEL, and then a variable number of arguments, which are, of course, unprototyped because depending on the method, those arguments could be anything.  This lack of a complete ANSI prototype can produce ill effects.  Without prototypes, arguments are subject to promotion.  Chars are promoted to int,  floats are promoted to double, and so on.  \
  27. \
  28. The concern is with floats.  Let's say you have a method that takes a float as an argument.  Objective-C methods conform to the ANSI prototyping rules and expect a 32-bit float to be put on the stack for that method.  And when that method is called normally, 32 bits are put on the stack and it all works out.  \
  29. \
  30. Now you get the IMP by calling methodFor: for that selector.  You try to directly call the function,  passing a float.  Because the function was not explicitly prototyped, old-style C takes over and that float is promoted to a 64-bit double.  When that 64 bits is placed on the stack for a method which expects a 32-bit float — catastrophe strikes!  The method tries to interpret the first 32 bits of the 64-bit double as a float, which doesn't work, and any arguments which follow the float in the parameter list are also messed up.\
  31. \
  32. The solution:  construct the proper prototype for the function pointer in question , something like this:\
  33. \
  34.  
  35. \f1\fs24      id   (*func)(id,SEL,float,...); \
  36.      \
  37.      func = (id (*)(id,SEL,float,...))[anObject methodFor:@selector(aSelector)];
  38. \f0\fs28 \
  39.      
  40. \f1\fs24    (* func)(anObject, @selector(aSelector), aFloat, otherArgs ...);\
  41.  
  42. \f0\fs28 \
  43. The prototype ensures that methodFor: returns a pointer to a function that returns an id and has the arguments an id, a selector, a float, and other variable arguments.  If the sight of prototypes scares you, another solution is to structure the necessary methods to simply take doubles.\
  44. \
  45. You must take similar precautions and coerce the return value when the method does not return an id.  Here floatValue is a method which returns a float.\
  46. \
  47.  
  48. \f1\fs24     float   (*getFloat)();\
  49.     float    value;\
  50.     \
  51.     getFloat = (float (*)())[anObject methodFor:@selector(floatValue)];\
  52.     value = (* getFloat)(anObject, @selector(floatValue)));\
  53.  
  54. \f0\fs28 \
  55. QA219\
  56. \
  57. Valid for 1.0, 2.0, 3.0\
  58. \
  59.  
  60.